import cv2 as cv
import time
##以Lena为原始图像，通过OpenCV使用Sobel及Canny算子检测，比较边缘检测结果。

# 在Sobel函数的第二个参数这里使用了cv2.CV_16S。因为OpenCV文档中对Sobel算子的介绍中有这么一句:“in the case of 8-bit input images it will result in truncated derivatives”。即Sobel函数求完导数后会有负值,还有会大于255的值。而原图像是uint8,即8位无符号数,所以Sobel建立的图像位数不够,会有截断。因此要使用16位有符号的数据类型,即cv2.CV_16S。在经过处理后,别忘了用convertScaleAbs()函数将其转回原来的uint8形式。否则将无法显示图像,而只是一副灰色的窗口。convertScaleAbs()的原型为:
# 	dst = cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])
#         其中可选参数alpha是伸缩系数,beta是加到结果上的一个值。结果返回uint8类型的图片。
#
# 由于Sobel算子是在两个方向计算的,最后还需要用cv2.addWeighted(...)函数将其组合起来。其函数原型为:
#         dst=cv2.addWeighted(src1,alpha,src2,beta,gamma[,dst[,dtype]])
#         其中alpha是第一幅图片中元素的权重,beta是第二个的权重,gamma是加到最后结果上的一个值。

#imread 第二参数设置为0,表示读出来的是灰度图, 不用再进行灰度转换了
# img = cv.imread("../pic/lena.jpg", 0)
img = cv.imread("../pic/1080p.jpg", 0)
cv.imshow('lena', img)
##X,Y方向分别计算差分
t1 = time.time()
sobelX = cv.Sobel(img, cv.CV_16S, 1,0)
sobelY = cv.Sobel(img, cv.CV_16S, 0,1)
#转回8-bit
absX = cv.convertScaleAbs(sobelX)
absY = cv.convertScaleAbs(sobelY)
#合并结果
merge = cv.addWeighted(absX, 0.5, absY, 0.5, 0)
t2 = time.time()
cv.imshow('sobel-0', merge)
print("sobel use ", 1000*(t2-t1), "ms")
# cv.imshow('absX', absX)
# cv.imshow('absY', absY)
# cv.imshow('sobel-0', merge)
# merge = cv.addWeighted(absX, 0.5, absY, 0.5, 1)


####canny边缘提取
t1 = time.time()
canny = cv.Canny(img, 50,150)
t2 = time.time()
print("canny use", 1000*(t2-t1),"ms")
cv.imshow('canny', canny)

##先高斯滤波再转灰度再canny：效果会更好
t1 = time.time()
blur = cv.GaussianBlur(img, (3,3), 1.0)
gCanny = cv.Canny(blur, 50, 150)
t2 = time.time()
print("gause + canny use", 1000*(t2-t1),"ms")
cv.imshow('gause-canny', gCanny)

cv.waitKey()